﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading ;
using System.IO;
 
using Lidgren.Network;
using IMLibrary.Net.Enum;


namespace IMLibrary.NetClient
{
    /// <summary>
    /// p2p客户端
    /// </summary>
    public class P2PClientV1
    {
        #region 构造函数
        /// <summary>
        ///  p2p客户端
        /// </summary>
        /// <param name="serverIP"></param>
        /// <param name="serverPort"></param>
        /// <param name="isServer">是否服务方(即发送方)</param>
        /// <param name="netDelivery">网络数据交换方式(可靠有序、不可靠有序、可靠无序、不可靠无序等)</param>
        public P2PClientV1(string serverIP, int serverPort, bool isServer, NetDelivery netDelivery)//= NetDelivery.ReliableOrdered
        {
            masterServer = NetUtility.Resolve(serverIP, serverPort);
            ServerIP = serverIP;
            ServerPort = serverPort;
           
            NetPeerConfiguration config = new NetPeerConfiguration("P2PClient");
            config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
            config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
            config.AutoFlushSendQueue = true;
            config.EnableUPnP = true;
            IsServer = isServer;

            if (IsServer)
            { 
                Peer = new NetServer(config);
            }
            else
            { 
                Peer = new Lidgren.Network.NetClient(config); ;
            }

            this.netDeliveryMethod = (NetDeliveryMethod)netDelivery;
        }
        #endregion

        #region 字段
        /// <summary>
        /// 
        /// </summary>
        NetPeer Peer=null;
        /// <summary>
        /// 
        /// </summary> 
        NetDeliveryMethod netDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
        /// <summary>
        /// 服务器IP
        /// </summary>
        public string ServerIP
        {
            private set;
            get;
        }
        /// <summary>
        /// 服务器端口
        /// </summary>
        public int ServerPort
        {
            private set;
            get;
        }
        /// <summary>
        /// 服务器中转端口
        /// </summary>
        public int ServerTurnPort
        {
            private set;
            get;
        }
        /// <summary>
        /// 是否发送方
        /// </summary>
        bool IsServer = true; 
        /// <summary>
        /// 是否从主服务器获得自身服务ID
        /// </summary>
        bool IsGetServerID = false;
        /// <summary>
        /// 
        /// </summary>
        System.Timers.Timer timer = null;
        /// <summary>
        /// 
        /// </summary>
        System.Timers.Timer RegServerTimer =null;
        /// <summary>
        /// 远程主机ID
        /// </summary>
        long RemoteHostid = 0;
        /// <summary>
        /// 本地主机ID
        /// </summary>
        long LocalHostid = 0; 
        /// <summary>
        /// 是否中转
        /// </summary>
        bool Turning = false;
        /// <summary>
        /// 
        /// </summary>
        SendOrPostCallback CallGetMessage = null;
    
        #endregion

        #region 属性
        /// <summary>
        /// MTU 最大网络传输单元
        /// </summary>
        public int MTU
        {
            get
            {
                return 12000;//Peer.Connections[0].Peer.Configuration.MaximumTransmissionUnit - 20; return 51200;
            }
        }

        /// <summary>
        /// 服务器节点
        /// </summary>
        private IPEndPoint masterServer
        {
            set;
            get;
        }

        /// <summary>
        /// 远程节点
        /// </summary>
        public IPEndPoint RemoteIPEndPoint
        {
            get;
            private set;
        }
        /// <summary>
        /// 是否启动服务
        /// </summary>
        public bool  IsStartServer
        {
            get;
            private set;
        }
        private ConnectionType _ConnectionType = ConnectionType.None;
        /// <summary>
        /// 是否连接服务器
        /// </summary>
        public ConnectionType ConnectionType
        {
            get
            {
                return _ConnectionType;
            }
        }
        #endregion

        #region 事件
        public delegate void EventHandler(object sender, UDPEventArgs e);
        /// <summary>
        /// 客户端已联接事件
        /// </summary>
        public event EventHandler Connected;
        private void onConnected(UDPEventArgs e)
        {
            if (Connected != null)
                Connected(this, e);

        }
        /// <summary>
        /// 注册服务成功事件
        /// </summary>
        public event EventHandler ServerRegistered;
        private void onServerRegistered(UDPEventArgs e)
        {
            if (ServerRegistered != null && !IsGetServerID)
            {
                IsGetServerID = true;
                ServerRegistered(this, e);
            }
        }
        /// <summary>
        /// 联接断开事件
        /// </summary>
        public event EventHandler Disconnected;
        private void onDisconnected(UDPEventArgs e)
        {
            if (Disconnected != null)
                Disconnected(this, e);

        }
        /// <summary>
        /// 不能建立联接事件
        /// </summary>
        public event EventHandler Dotconnect;
        private void onDotconnect(UDPEventArgs e)
        {
            if (Dotconnect != null)
                Dotconnect(this, e);

        }

        /// <summary>
        /// 不能建立联接事件
        /// </summary>
        public event EventHandler RequestSend;
        private void onRequestSend(UDPEventArgs e)
        { 
            if (RequestSend != null)
                RequestSend(this, e); 
        }
 
        /// <summary>
        /// 收到消息事件
        /// </summary>
        public event EventHandler RecivedData;
        private void onRecivedData(UDPEventArgs e)
        {
            if (RecivedData != null)
                RecivedData(this, e);
        }
        #endregion

        #region 请求NAT穿越
        /// <summary>
        /// 请求NAT穿越
        /// </summary>
        /// <param name="hostid">对端主机ID</param>
        public void RequestNATIntroduction(long hostid)
        {
            if (hostid == 0) return;
            RemoteHostid = hostid;

            if (masterServer == null)
                return;

            if (timer == null)
            {
                int count = 0;
                timer = new System.Timers.Timer(1000);
                timer.Elapsed += (s, e) =>
                {
                    count++;
                    if (count == 4 && _ConnectionType ==  ConnectionType.None)
                    {
                        if (!IsServer)
                            RequestTurn();//请求中转服务
                    }
                    if (count > 8)
                    {
                        CloseTimer();
                        if (_ConnectionType ==  ConnectionType.None)
                            onDotconnect(null);
                    }
                    if (_ConnectionType !=  ConnectionType.None)
                    {
                        CloseTimer();
                    }
                };
                timer.Enabled = true;
            }

            NetOutgoingMessage om = Peer.CreateMessage();
            om.Write((byte)MasterServerMessageType.RequestIntroduction);
            // write my internal ipendpoint
            IPAddress mask;
            om.Write(new IPEndPoint(NetUtility.GetMyAddress(out mask), Peer.Port));
            // write requested host id
            om.Write(hostid);
            // write token
            om.Write("Ourmsg");
            Peer.SendUnconnectedMessage(om, masterServer);
        }
        #endregion

        #region 向服务器请求中转
        /// <summary>
        /// 向服务器请求中转
        /// </summary>
        private void RequestTurn()
        {
            NetOutgoingMessage om;
            om = Peer.CreateMessage(); 
            om.Write((byte)MasterServerMessageType.RequestTurn);
            om.Write(RemoteHostid);
            Peer.SendUnconnectedMessage(om, masterServer);
        }
        #endregion

        #region 关闭并释放时钟
        private void CloseTimer()
        { 
            if (timer != null)
            {
                timer.Enabled = false;
                timer.Close(); timer.Dispose(); timer = null;
            }
            CloseRegTimer();
        }

        private void CloseRegTimer()
        {
            if (RegServerTimer != null)
            {
                RegServerTimer.Enabled = false;
                RegServerTimer.Close(); RegServerTimer.Dispose(); RegServerTimer = null;
            }
        }
        #endregion

        #region 服务
        /// <summary>
        /// 开始服务
        /// </summary>
        public void Start()
        {
            if (IsStartServer) 
                return;
            IsStartServer = true;

            CallGetMessage = new SendOrPostCallback(GetMessage);
            Peer.RegisterReceivedCallback(CallGetMessage);
            Peer.Start();
            if (Peer.UPnP != null)
            {
                var t = Peer.UPnP.ForwardPort(Peer.Port, "ourmsg" + Peer.Port.ToString());
                if (t)
                    Console.WriteLine("Upnp Success!");
                else
                    Console.WriteLine("Upnp failed!");
            }
            Register();
            if (RegServerTimer == null)
            {
                RegServerTimer = new System.Timers.Timer(10000);
                RegServerTimer.Elapsed += (s, e) =>
                    {
                        if (ConnectionType == ConnectionType.None)
                        {
                            Register();
                        }
                        else
                        {
                            CloseRegTimer();
                        }
                    };
            }
            RegServerTimer.Start();
        }
        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            if (CallGetMessage != null)
                Peer.UnregisterReceivedCallback(CallGetMessage);
            System.Threading.Thread.Sleep(500);
            if (Peer != null)
                Peer.Shutdown("shutdown");
            Peer = null;
            _ConnectionType = ConnectionType.None;
            IsStartServer = false;
        }
        #endregion

        #region 注册服务ID
        void Register()
        { 
            NetOutgoingMessage regMsg =Peer.CreateMessage();
            regMsg.Write((byte)MasterServerMessageType.RegisterHost);
            IPAddress mask;
            IPAddress adr = NetUtility.GetMyAddress(out mask);
            regMsg.Write(Peer.UniqueIdentifier);
            regMsg.Write(new IPEndPoint(adr, Peer.Port));
            Peer.SendUnconnectedMessage(regMsg, masterServer);
            Console.WriteLine("Sending registration to master server");
        }
        #endregion

        #region GetMessage
        private void GetMessage(object peer) 
        {
            try
            {
                NetIncomingMessage inc;
                while ((inc = Peer.ReadMessage()) != null)
                {
                    switch (inc.MessageType)
                    {
                        case NetIncomingMessageType.VerboseDebugMessage:
                        case NetIncomingMessageType.DebugMessage:
                        case NetIncomingMessageType.WarningMessage:
                        case NetIncomingMessageType.ErrorMessage:
                            Console.WriteLine(inc.ReadString());
                            break;
                        case NetIncomingMessageType.StatusChanged:
                            NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte();
                            switch (status)
                            {
                                case NetConnectionStatus.Connected:
                                    if (Turning)
                                        _ConnectionType =  ConnectionType.UDPTurn;
                                    else
                                        _ConnectionType =  ConnectionType.UDPDirect;
                                    onConnected(null);
                                    break;
                            }
                            break;
                        case NetIncomingMessageType.Data:
                            if (inc.DeliveryMethod == this.netDeliveryMethod) //NetDeliveryMethod.ReliableOrdered
                                onRecivedData(new UDPEventArgs(false, inc.ReadBytes(inc.LengthBytes), null));
                            break;
                        case NetIncomingMessageType.NatIntroductionSuccess:
                            {
                                if (_ConnectionType == ConnectionType.None)
                                {
                                    _ConnectionType = ConnectionType.UDPDirect;
                                    RemoteIPEndPoint = inc.SenderEndPoint;

                                    if (IsServer)//如果是请求端
                                        Send("OK");
                                    else
                                        Peer.Connect(inc.SenderEndPoint);
                                }
                            }
                            break;
                        case NetIncomingMessageType.UnconnectedData:
                            {
                                if (inc.SenderEndPoint.Equals(masterServer))
                                {
                                    var P = inc.ReadByte();
                                    if (P == (byte)MasterServerMessageType.RequestTurn)//中转数据
                                    {
                                        Turning = true;
                                        ServerTurnPort = inc.ReadInt32();//获得中转服务UDP端口
                                        if (IsServer)//如果是请求端 
                                        {
                                            NetOutgoingMessage om = Peer.CreateMessage();
                                            om.Write(true);
                                            Peer.SendUnconnectedMessage(om, ServerIP, ServerTurnPort);//向中转端口发送任一数据 
                                        }
                                        else
                                            Peer.Connect(ServerIP, ServerTurnPort);//连接中转端口 
                                    }
                                    else if (P == (byte)MasterServerMessageType.RegisterHost)
                                    {
                                        LocalHostid = inc.ReadInt64();
                                        var hostInternal = inc.ReadIPEndPoint();
                                        var hostExternal = inc.ReadIPEndPoint();
                                        onServerRegistered(new UDPEventArgs(LocalHostid));
                                    }
                                }
                                else
                                {
                                    if (_ConnectionType == ConnectionType.None)
                                    {
                                        _ConnectionType = ConnectionType.UDPDirect;
                                        RemoteIPEndPoint = inc.SenderEndPoint;
                                        if (!IsServer)//如果是请求端 
                                            Peer.Connect(inc.SenderEndPoint);//连接中转端口
                                    }
                                }
                            }
                            break;
                    }
                }
            }
            catch { }
        }
        #endregion

        #region 清空发送缓冲区
        /// <summary>
        /// 清空发送缓冲区
        /// </summary>
        public void FlushSendQueue()
        {
            if (Peer.ConnectionsCount > 0)
            {
                Peer.FlushSendQueue();
            }
        }
        #endregion

        #region 发送消息
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        void Send(string data)
        {
            Send(Encoding.UTF8.GetBytes(data));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        void Send(byte[] data)
        {
            NetOutgoingMessage om =Peer.CreateMessage();
            if (ConnectionType ==  ConnectionType.UDPDirect)
            {
                om.Write(data);
                Peer.SendUnconnectedMessage(om, RemoteIPEndPoint);
            }
            else if (ConnectionType ==  ConnectionType.UDPTurn)
            {
                om.Write((byte)MasterServerMessageType.RequestTurn);
                om.Write(RemoteHostid);
                om.Write(LocalHostid);
                om.Write(data);
                Peer.SendUnconnectedMessage(om, masterServer);
            }
        }

        public void SendConnectData(string data)
        {
            SendConnectData(Encoding.UTF8.GetBytes(data));
        }

        public void SendConnectData(byte[] data)
        {
            try
            {
                if (ConnectionType != ConnectionType.None && Peer.ConnectionsCount > 0)
                {
                    NetOutgoingMessage om;
                    om = Peer.Connections[0].Peer.CreateMessage(data.Length);
                    om.Write(data);
                    Peer.Connections[0].SendMessage(om, this.netDeliveryMethod, 0);// NetDeliveryMethod.ReliableOrdered
                }
            }
            catch { }
        }
        #endregion
    }
}
